/*******************************************************************************
 * @note Copyright (C) 2011-2022， Shanghai Panchip Microelectronics Co., Ltd. 
 * @SPDX-License-Identifier: Apache-2.0
 * @history - V0.1, 2022-09-28
*******************************************************************************/
#include "at.h"
#include "user.h"
#include "hardware.h"
#include "service_nodemode.h"
#include "service_net.h"
#ifdef USBDONGLE
#include "ds18b20.h"
#include "hal_pwm.h"
#endif

net_proc_t net_proc;

chirp_app_data_t app_data;

extern node_config_t node_config;
extern rf_config_t pn3028_config;
extern uint8_t radio_irq_flag;

extern chirp_function_s chirpmac_function;
extern uint32_t freq_table[DEFAULT_FREQ_TABLE_NUM];
chirp_t chirp_config;
void net_check_do_next(void);

#ifdef USBDONGLE
uint8_t temp_interval = 10;
uint8_t rgb_blue = 0;
uint8_t rgb_red = 0;
#endif
void net_chirp_recv_cb( void )
{
	if((chirp_config.config.workmode == CHIRP_CLASS_B) && (chirp_config.app_data.RxLen == 0))
	{
		stimer_stop(&net_proc.stimer_chirp_rx);
		net_proc.evt |= NET_EVT_CHIRP_RX_TIMEOUT;
	}

	if(chirp_config.app_data.RxLen != 0)
	{
		#ifdef USBDONGLE
		if((chirp_config.app_data.RxBuff[0] == 0xbb)&&(chirp_config.app_data.RxLen == 4))
		{
			rgb_blue = chirp_config.app_data.RxBuff[2];
			rgb_red = chirp_config.app_data.RxBuff[1];

			PWM_Set_RGB((chirp_config.app_data.RxBuff[1]<<16) | (chirp_config.app_data.RxBuff[2]<<8));
			if(chirp_config.app_data.RxBuff[3] != 0)
			{
				temp_interval = chirp_config.app_data.RxBuff[3];
			}
		}
		#endif
		net_proc.evt |= NET_EVT_CHIRP_RX_DONE;
		memcpy(net_proc.rf_msg.buf, chirp_config.app_data.RxBuff, chirp_config.app_data.RxLen);
		net_proc.rf_msg.len = chirp_config.app_data.RxLen;
		chirp_config.app_data.RxLen = 0;	
	}
}

void net_chirp_join_cb( void )
{
	
}

void net_chirp_config_cb( void )
{
	node_config.net_class = chirp_config.config.workmode;
	node_config.wakeup_time = chirp_config.config.rf_config.rxsleeptime;
}

void net_chirp_send_cb( void )
{
    if ( net_proc.status != NET_STATUS_INITIALIZED )
    {
        return;
    }
    else if ( node_config.work_mode != WORKMODE_NET )
    {
        return;
    }
    
    net_proc.evt |= NET_EVT_CHIRP_TX_DONE;
	
	if(chirp_config.all_status.send_status == CHIRP_SEND_OK)
	{
	}
	
	if(chirp_config.all_status.send_status == CHIRP_SEND_ERR)
	{
	}

	chirp_config.all_status.send_status = CHIRP_SEND_IDLE;
}

void net_io_set_evt(void)
{
    /* if pt process is not initialized, suspend the process. */
    if (net_proc.status != NET_STATUS_INITIALIZED)
    {
        return;
    }

    if ( GPIO_SETB_LEVEL_GET() == LEVEL_ACTIVE )
    {
        net_proc.evt |= NET_EVT_SETB_ACTIVE;
    }
    else
    {
        net_proc.evt |= NET_EVT_SETB_INACTIVE;
    }
}

void net_uart_set_evt(void)
{
    if ( net_proc.status != NET_STATUS_INITIALIZED
         || node_config.work_mode != WORKMODE_NET
         || fifo_is_empty(&uart_rx_fifo))
    {
        return;
    }

    net_proc.evt |= NET_EVT_UART_RX_DONE;
}

void net_uart_rx_timeout_cb(void)
{
    net_debug("");
    net_proc.evt |= NET_EVT_UART_RX_TIMEOUT;
}

void net_chirp_tx_timeout_cb(void *ptr)
{
    net_debug("");
    net_proc.evt |= NET_EVT_CHIRP_TX_TIMEOUT;
}

void net_chirp_rx_timeout_cb(void *ptr)
{
    net_debug("");
    net_proc.evt |= NET_EVT_CHIRP_RX_TIMEOUT;
}

void net_chirp_cad_chk_timeout_cb(void *ptr)
{
    net_debug("");
    net_proc.evt |= NET_EVT_CAD_CHECK_TIMEOUT;
	
	chirpmac_function.Wakeup();
}

#ifdef USBDONGLE
void net_chirp_send_18b20_temp_cb(void *ptr)
{
    net_debug("");
    net_proc.evt |= NET_EVT_SEND_18B20_TEMP;
}
#endif

/*
 * uart received data handle
 */
int net_uart_data_handle(net_proc_t *proc)
{
    net_msg_t *p = &proc->uart_msg;
    
    p->len = uart_fifo_read(p->buf, NET_BUF_SIZE);

	if(p->len == 0)
	{
		return -1;
	}
		
    if ( aux_mode == AUX_MODE_EMPTY )
    {
        if ( fifo_is_empty(&uart_rx_fifo) )
        {
            aux_level_set(AUX_FIFO, LEVEL_INACTIVE);
        }
        else
        {
            aux_level_set(AUX_FIFO, LEVEL_ACTIVE);
        }
    }
    else //AUX_MODE_FULL
    {
        aux_level_set(AUX_FIFO, LEVEL_INACTIVE);
    }

    /* BEGIN: check +++ cmd */
    if(proc->net_switch == NET_SWITCH_STATE_IDLE)
    {
        if (p->len == 3)
        {
            p->buf[3] = 0;
            if ( strstr((char *)p->buf, "+++") )
            {

#ifdef DDL_UART_DMA_YES
                hw_uart0_dma_send("a", 1);
#else
                uart0_sendBuf("a", 1);
#endif

                /* switch to ack state */
                proc->net_switch = NET_SWITCH_STATE_WACK;
                return -1;
            }
        }
    }
    else if (proc->net_switch == NET_SWITCH_STATE_WACK)
    {
        if(p->len==1&&p->buf[0]=='a')
        {
#ifdef DDL_UART_DMA_YES
            hw_uart0_dma_send("OK\r\n", 4);
#else
            uart0_sendBuf("OK\r\n", 4);
#endif

            /* enter at mode */
            nm_enter_at_mode();
            nm_set_at_op();
            proc->net_switch = NET_SWITCH_STATE_IDLE;
            return -1;
        }
    }
    /* END: check +++ cmd */

    proc->net_switch = NET_SWITCH_STATE_IDLE;
    
    if ( proc->state == NET_STATE_JOIN )
    {
        return -1;
    }

    app_data.TxLen = p->len;
    memcpy(app_data.TxBuff, p->buf, p->len);

    /* push datas to chirp tx fifo */
	if(node_config.net_dack_enbale == TRUE)
	{
		if(chirpmac_function.Send(&app_data, CHIRP_CONFIRMED_MSG, net_chirp_send_cb) != CHIRPLAN_STATUS_OK)
		{
			uart_rx_fifo_flush();
			return -1;
		}
		
	}else{
		if(chirpmac_function.Send(&app_data, CHIRP_UNCONFIRMED_MSG, net_chirp_send_cb) != CHIRPLAN_STATUS_OK)
		{
			uart_rx_fifo_flush();
			return -1;
		}
	}
    
    print_hex(p->buf, p->len);
    
    proc->evt &= ~NET_EVT_CHIRP_TX_DONE;
    stimer_stop(&proc->stimer_chirp_rx);
    stimer_set(&proc->stimer_chirp_tx, 15000, STIMER_MODE_ONESHOT,\
               net_chirp_tx_timeout_cb, NULL);

    return 0;
}

/**
 * @brief Call this function every time you finish some opertion.
 * @param[in] <none>
 * @return <none>
 */
void net_check_do_next(void)
{
    /* check something have not done? */
    /* if node is working is CHIRP_CLASS_A */
    if ( GPIO_SETB_LEVEL_GET() == LEVEL_ACTIVE
         &&(node_config.net_class == CHIRP_CLASS_A
            ||node_config.net_class == CHIRP_CLASS_C)
         && net_proc.evt&NET_EVT_UART_RX_DONE )
    {
        /* jump to idle state to do what hasn't been done yet */
        net_proc.state = NET_STATE_IDLE;
        return;
    }
    /* if node is in timed wakeup mode */
    else if ( GPIO_SETB_LEVEL_GET() == LEVEL_INACTIVE
              && node_config.net_class == CHIRP_CLASS_B
              && net_proc.evt&NET_EVT_CHIRP_RX_DONE )
    {
        /* jump to idle state to do what hasn't been done yet */
        net_proc.state = NET_STATE_IDLE;
        return;
    }

    aux_level_set(AUX_FIFO, LEVEL_INACTIVE);
    
    if ( node_config.net_class == CHIRP_CLASS_A )
    {
        /* enable uart tx&rx */
        Uart_EnableFunc(M0P_UART0, UartRenFunc);

        if ( GPIO_SETB_LEVEL_GET() == LEVEL_ACTIVE )
        {
            /* jump to idle state */
            net_proc.state = NET_STATE_IDLE;
        }
        else
        {
			net_proc.rtc_on = FALSE;
            /* jump to sleep state */
            net_proc.state = NET_STATE_SLEEP;
        }
    }
    /* classb ignore the level of setb */
    else if ( node_config.net_class == CHIRP_CLASS_B )
    {
        if (check_cad_rx_inactive()==LEVEL_ACTIVE)
        {net_debug("");
			rf_set_cad_off();
            /* start stimer for rf receiving timeout */
            stimer_stop(&net_proc.stimer_chirp_tx);
            stimer_set(&net_proc.stimer_chirp_rx,  \
					//chirp_config.config.rf_config.rxsleeptime
                       node_config.rf_rx_timeout,    \
                       STIMER_MODE_ONESHOT,        \
                       net_chirp_rx_timeout_cb, NULL);

            /* ChirpLAN enter recv state */
			chirpmac_function.ClassBRx();
            /* jump to idle state */
            net_proc.state = NET_STATE_IDLE;
        }
        else/* if cad signal is inactive */
        {net_debug("");
			rf_set_cad_off();
            if ( GPIO_SETB_LEVEL_GET() != LEVEL_ACTIVE )
			{
				/* jump to sleep state */
				net_proc.state = NET_STATE_SLEEP;
				net_proc.rtc_on = TRUE;			
			}else
			{
				chirpmac_function.Sleep();
				net_debug("%d",node_config.wakeup_time);
				stimer_stop(&net_proc.stimer_chirp_tx);
				stimer_stop(&net_proc.stimer_chirp_rx);	
				stimer_set(&net_proc.stimer_cad_chk,  \
						   node_config.wakeup_time,    \
						   STIMER_MODE_ONESHOT,        \
						   net_chirp_cad_chk_timeout_cb, NULL);
				/* jump to idle state */
				net_proc.state = NET_STATE_IDLE;
			}
        }
    }
    else if ( node_config.net_class == CHIRP_CLASS_C )
    {
        if (GPIO_SETB_LEVEL_GET() == LEVEL_ACTIVE)
        {
            /* enable uart tx&rx */
            Uart_EnableFunc(M0P_UART0, UartRenFunc);
			#ifdef USBDONGLE
            /* chirplan enter recv state */
			stimer_set(&net_proc.stimer_18b20_send,  \
					   1000*temp_interval,    \
					   STIMER_MODE_ONESHOT,        \
					   net_chirp_send_18b20_temp_cb, NULL);
			#endif
            /* jump to idle state */
            net_proc.state = NET_STATE_IDLE;
        }
        else
        {
			net_proc.rtc_on = FALSE;
            /* jump to sleep state */
            net_proc.state = NET_STATE_SLEEP;
        }
    }
}


void net_enter_sleep(int rtc_enable)
{
    aux_level_set(AUX_SLEEP, LEVEL_ACTIVE);
	net_debug("");
    net_proc.evt = NET_EVT_NONE;

	chirpmac_function.Sleep();
    
    stimer_stop(&net_proc.stimer_chirp_tx);
    stimer_stop(&net_proc.stimer_chirp_rx);
    stimer_stop(&net_proc.stimer_uart_rx);
	stimer_stop(&net_proc.stimer_cad_chk);
	hw_rtc_cfg(rtc_enable, node_config.wakeup_time/1000.0f);
    mcu_enter_lp();
}

void net_exit_sleep(void)
{
    hw_rtc_cfg(FALSE, node_config.wakeup_time/1000.0f);
    mcu_exit_lp();
    net_debug("");
    chirpmac_function.Wakeup();
	net_check_do_next();

	aux_level_set(AUX_SLEEP, LEVEL_INACTIVE);
}

void net_process(void)
{
    int ret;
    
    if (net_proc.status != NET_STATUS_INITIALIZED)
    {
        return;
    }
    
    chirplan_mac_process();
    
    switch ( net_proc.state )
    {
        case NET_STATE_INIT :
            net_debug("NET_STATE_INIT");
            net_proc.state = NET_STATE_JOIN;
            break;
        case NET_STATE_JOIN :
            /*have not joined in the gate way */
            if ( chirpmac_function.GetJoinStatus() != CHIRP_SET )
            {
                /* when chirp is in idle&not joined state, 
                   execute join operation */
                if (chirpmac_function.GetStatus() == CHIRP_STATE_IDLE)
                {
                    chirplan_status_t status;
                    pc_debug("");
                    status = chirpmac_function.Join(NULL);
                    if ( status == CHIRPLAN_STATUS_OK)
                    {
                       net_debug("");
                    }
                    else
                    {
                        net_debug("chirplan join fail");
                    }
                }
            }
            else /* join ok */
            {
                net_debug("join ok");
                
                /* AUX is setted into low level indicate node init success. */
                aux_level_set(AUX_JOIN, LEVEL_INACTIVE);
                
                net_check_do_next();
            }

            if ( net_proc.evt&NET_EVT_UART_RX_DONE )
            {
                net_debug("NET_EVT_UART_RX_DONE");
                net_proc.evt &= ~NET_EVT_UART_RX_DONE;

                /* pop data from uart rxfifo and push them to chirp */
                net_uart_data_handle(&net_proc);
            }

            break;
        case NET_STATE_IDLE :
        case NET_STATE_RX :
            if ( net_proc.evt&NET_EVT_SETB_ACTIVE )
            {
                net_debug("NET_EVT_SETB_ACTIVE");
                net_proc.evt &= ~NET_EVT_SETB_ACTIVE;
                
            }
            else if( net_proc.evt&NET_EVT_SETB_INACTIVE )
            {
                net_debug("NET_EVT_SETB_INACTIVE");
                net_proc.evt &= ~NET_EVT_SETB_INACTIVE;
                net_check_do_next();
            }
            else if ( net_proc.evt&NET_EVT_UART_RX_DONE )
            {
                net_debug("NET_EVT_UART_RX_DONE");
                net_proc.evt &= ~NET_EVT_UART_RX_DONE;
				if ( node_config.net_class == CHIRP_CLASS_B )	
				{
					chirpmac_function.Wakeup();
					stimer_stop(&net_proc.stimer_cad_chk);
				}	

                /* pop data from uart rxfifo and push them to chirp */
                int ret = net_uart_data_handle(&net_proc);

                if ( ret == 0 )
                {
                    /* jump to send state */
                    net_proc.state = NET_STATE_TX;
                }
            }
            else if ( net_proc.evt&NET_EVT_CHIRP_RX_DONE )
            {
                net_debug("NET_EVT_CHIRP_RX_DONE");
                net_proc.evt &= ~NET_EVT_CHIRP_RX_DONE;
 
                /*send the rf received datas through the uart port*/
                aux_level_set(AUX_DATA, LEVEL_ACTIVE);
                
                delay1ms(node_config.aux_head_time);//aux head delay time
                /* output the package of the chirp to uart interface */
                
            #ifdef DDL_UART_DMA_YES
                hw_uart0_dma_send(net_proc.rf_msg.buf, net_proc.rf_msg.len);
            #else
                uart0_sendBuf(net_proc.rf_msg.buf, net_proc.rf_msg.len);
            #endif

                delay1ms(node_config.aux_tail_time);//aux tail delay time
                
                aux_level_set(AUX_DATA, LEVEL_INACTIVE);
                
                /* check next work and do it */
                net_check_do_next();
            }
            else if ( net_proc.evt&NET_EVT_UART_RX_TIMEOUT )
            {
                net_debug("NET_EVT_UART_RX_TIMEOUT");
                net_proc.evt &= ~NET_EVT_UART_RX_TIMEOUT;
                
                stimer_stop(&net_proc.stimer_uart_rx);
                
                /* check next work and do it */
                net_check_do_next();
            }
            else if ( net_proc.evt&NET_EVT_CHIRP_RX_TIMEOUT )
            {
                net_debug("NET_EVT_CHIRP_RX_TIMEOUT");
                net_proc.evt &= ~NET_EVT_CHIRP_RX_TIMEOUT;
                
                stimer_stop(&net_proc.stimer_chirp_rx);
                
                /* check next work and do it */
                net_check_do_next();
            }
			else if(net_proc.evt&NET_EVT_CAD_CHECK_TIMEOUT)
			{
				net_proc.evt &= ~NET_EVT_CAD_CHECK_TIMEOUT;
				
				stimer_stop(&net_proc.stimer_cad_chk);
                /* check next work and do it */
                net_check_do_next();
			}
			#ifdef USBDONGLE
			else if(net_proc.evt&NET_EVT_SEND_18B20_TEMP)
			{
				net_proc.evt &= ~NET_EVT_SEND_18B20_TEMP;
				
				stimer_stop(&net_proc.stimer_18b20_send);
				

				static float temper = 0.0;

				temper=DS18B20_GetTemperture();
				
				app_data.TxLen = 5;
				app_data.TxBuff[0]  = 0xAA;
				app_data.TxBuff[1]  = (uint16_t)(temper*100)/100;
				app_data.TxBuff[2]  = (uint16_t)(temper*100)%100;
				app_data.TxBuff[3]  = rgb_red;
				app_data.TxBuff[4]  = rgb_blue;
				
				if(node_config.net_dack_enbale == TRUE)
				{
					chirpmac_function.Send(&app_data, CHIRP_CONFIRMED_MSG, net_chirp_send_cb);
					
				}else{
					chirpmac_function.Send(&app_data, CHIRP_UNCONFIRMED_MSG, net_chirp_send_cb);
				}				
				
                /* check next work and do it */
                net_check_do_next();
			}
			#endif
            break;
        case NET_STATE_TX:
            if(net_proc.evt&NET_EVT_CHIRP_TX_DONE)
            {
                net_proc.evt &= ~NET_EVT_CHIRP_TX_DONE;

                net_debug("tx pkgs success[len:%d]", net_proc.uart_msg.len);

                /* stop the chirp send timer */
                stimer_stop(&net_proc.stimer_chirp_tx);

                net_check_do_next();
            }
            else if ( net_proc.evt&NET_EVT_CHIRP_TX_TIMEOUT )
            {
                net_debug("NET_EVT_CHIRP_TX_TIMEOUT");
                net_proc.evt &= ~NET_EVT_CHIRP_TX_TIMEOUT;
                
                net_check_do_next();
            }
            else if (net_proc.evt&NET_EVT_UART_TX_DONE)
            {
                net_debug("NET_EVT_UART_TX_DONE");
                net_proc.evt &= ~NET_EVT_UART_TX_DONE;
                net_check_do_next();
            }
            break;
        case NET_STATE_SLEEP :
            net_enter_sleep(net_proc.rtc_on);
            net_exit_sleep();
            break;
        default:
            net_proc.state = NET_STATE_INIT;
            break;
    }
}

void net_clean(void)
{
    net_proc.status = NET_STATUS_UNINITIALIZED;
    net_proc.count = 0;
    net_proc.state = NET_STATE_INIT;
    net_proc.evt = NET_EVT_NONE;

    stimer_stop(&net_proc.stimer_chirp_tx);
    stimer_stop(&net_proc.stimer_chirp_rx);
    stimer_stop(&net_proc.stimer_uart_rx);
	stimer_stop(&net_proc.stimer_cad_chk);
	#ifdef USBDONGLE
	stimer_stop(&net_proc.stimer_18b20_send);
	#endif
	chirpmac_function.StatusReset();
}

/*
 * 获取ChirpLAN相关配置参数
 */
void net_get_config(chirp_t *config)
{
    config->config.crypt.enable = node_config.aes_enable;
    memcpy(config->config.crypt.aes_key, node_config.aes_key, sizeof(node_config.aes_key));

    config->config.workmode = node_config.net_class;

    config->config.netid.app_id = node_config.app_id;
    config->config.netid.node_id = node_config.node_id;
    config->config.netid.gw_net_id = node_config.gw_id;

    config->config.rf_config.ch = 3;
    config->config.rf_config.bw = pn3028_config.bw;
    config->config.rf_config.sf = pn3028_config.sf;
    config->config.rf_config.cr = pn3028_config.cr;
    config->config.rf_config.crc = pn3028_config.crc;
    config->config.rf_config.ldr = pn3028_config.ldr;
    config->config.rf_config.preambletime = pn3028_config.preamble;
    config->config.rf_config.tx_power = pn3028_config.pwr;
    config->config.rf_config.rxwindow = node_config.rf_rx_window;/*mode A/C rx window*/
	config->config.rf_config.rxsleeptime = node_config.wakeup_time;/*mode B wakeup time*/
	
	memcpy(freq_table, node_config.channel_up , DEFAULT_FREQ_TABLE_NUM*4);
}

void net_init(void)
{
    chirplan_status_t status;

    /* indicating node is initializing */
    aux_level_set(AUX_JOIN, LEVEL_ACTIVE);
	#ifdef USBDONGLE
    PWM_Set_RGB(0xff);
	#endif
    net_proc.count = 0;
    net_proc.state = NET_STATE_INIT;
    net_proc.evt = NET_EVT_NONE;
    net_proc.status = NET_STATUS_INITIALIZED;

    net_get_config(&chirp_config);

    status = chirpmac_function.MacInit(&chirp_config,net_chirp_config_cb);
	chirpmac_function.Recv(net_chirp_recv_cb);
	chirpmac_function.Send(NULL,chirp_config.config.confirm,net_chirp_send_cb);
    if ( status == CHIRPLAN_STATUS_OK)
    {
        net_proc.status = NET_STATUS_INITIALIZED;
    }
    else
    {
        net_debug("chirplan_init fail");
        aux_level_set(AUX_ERROR, LEVEL_ACTIVE);
    }
    
    net_debug("net process init");
}

